from PyQt5.QtCore import QThread, pyqtSignal

from alphazero_model_rk import AlphaZeroRKPlayer, load_rknn_model
from game_logic import GameLogic
from decision_util import GameStatus, DecisionUtil

from loguru import logger
import cv2
import serial
import traceback


def get_game_logic(
    cam_dev: str,
    ser_dev: str,
    first_act: GameStatus,
    bot_role: int,
    player: AlphaZeroRKPlayer,
):
    cap = cv2.VideoCapture(cam_dev)
    cap.set(3, 680)
    cap.set(4, 480)

    try:
        driver = serial.Serial(ser_dev, 115200, timeout=1)
        assert driver.is_open
        decision = DecisionUtil(driver)
    except Exception as e:
        logger.error(f"Failed to connect to {ser_dev}: {e}")

    logger.info("serial ok")

    # use MCTS player
    # player = MCTSPlayer(simulations=1000)

    # use AlphaZeroRK player

    return GameLogic(
        cap,
        first_act,
        bot_role,
        player,
        decision,
    )


class GameThread(QThread):
    status_trigger = pyqtSignal(GameStatus)

    def __init__(self, game_logic: GameLogic):
        super().__init__()
        self.game_logic = game_logic

    def run(self):
        try:
            self.game_logic.get_decision().reset()
            self.game_logic.game(self.status_trigger.emit)
        except:
            logger.error(f"Game thread error: {traceback.format_exc()}")

    def userActDone(self):
        self.game_logic.get_decision().user_acting_done()


class ResetBoardThread(QThread):
    def __init__(self, game_logic: GameLogic):
        super().__init__()
        self.game_logic = game_logic

    def run(self):
        try:
            self.game_logic.get_decision().reset()
            logger.debug("Reset board thread started")
            self.game_logic.game(None, reset_board_only=True)
        except:
            logger.error("Reset board thread error")


class TestThread(QThread):
    def __init__(self, game_logic: GameLogic, target_color, target_posi):
        super().__init__()
        self.game_logic = game_logic
        self.target_color = target_color
        self.target_posi = target_posi

    def run(self):
        try:
            self.game_logic.get_decision().reset()
            self.game_logic.test(self.target_color, self.target_posi)
        except:
            logger.error("Test thread error")
